#include <string>
#include <sstream>
#include <cstdlib>

using namespace std;

namespace math {

	// Classe per gestire i numeri complessi

	class Complex {
		private:
			float real, immaginary;
		public:
			// Dichiarazione dei costruttori
			Complex(float r = 0, float i = 0);

			// Dichiarazione dei getters e dei setters
			float getReal() const;
			void setReal(float r);
			float getImmaginary() const;
			void setImmaginary(float i);

			// Dichiarazione degli operatori
			Complex operator+= (const Complex &c);
			Complex operator-= (const Complex &c);
			Complex operator= (const Complex &c);
			//Complex operator+ (const Complex *c1, const Complex *c2);
			Complex operator+ (const Complex &c);
			Complex operator- (const Complex &c);

			string toString();
	};

	Complex::Complex(float r, float i) {
		real = r;
		immaginary = i;
	}

	// Implemento getters e setters

	float Complex::getReal() const {
		return this -> real;
	}

	void Complex::setReal(float r) {
		this -> real = r;
	}

	float Complex::getImmaginary() const {
		return this -> immaginary;
	}

	void Complex::setImmaginary(float i) {
		this -> immaginary = i;
	}

	// Implemento l'overload degli operatori

	Complex Complex::operator+=(const Complex &c) {
		this -> setReal (this -> getReal() + c.getReal());
		this -> setImmaginary (this -> getImmaginary() + c.getImmaginary());
		return *this;
	}

	Complex Complex::operator-= (const Complex &c) {
		this -> setReal (this -> getReal() - c.getReal());
		this -> setImmaginary (this -> getImmaginary() + c.getImmaginary());
		return *this;
	}

	Complex Complex::operator= (const Complex &c) {
		this -> setReal(c.getReal());
		this -> setImmaginary (c.getImmaginary());
		return *this;
	}

	Complex Complex::operator+ (const Complex &c) {
		Complex *result = new Complex();
		result -> setReal (this -> getReal() + c.getReal());
		result -> setImmaginary (this -> getImmaginary() + c.getImmaginary());
		return *result;
	}

	Complex Complex::operator- (const Complex &c) {
		Complex *result = new Complex();
		result -> setReal (this -> getReal() - c.getReal());
		result -> setImmaginary (this -> getImmaginary() - c.getImmaginary());
		return *result;
	}

	// Metodo per la stampa di un complesso sottoforma di stringa

	string Complex::toString() {
		stringstream result;
		( immaginary >= 0 ) ?
			result << real << "+" << immaginary << "i" : 
			result << real << "-" << (-immaginary) << "i";
		return result.str();
	}
          
	// Classe per la gestione delle matrici
          
	class Matrix {
		private:
			int rows, columns;
			int **matrix;
		public:
			Matrix (int r, int c) throw (char *);
			Matrix (int **m);
			int getRows();
			int getColumns();
			int** getMatrix();

			string toString();
	};

	Matrix::Matrix(int r, int c) throw (char *) {	
		if (r && c) {
			this -> rows = r;
			this -> columns = c;
			matrix = (int **) malloc(c * sizeof(int *));
			for (int i = 0; i < r; i++)
				matrix[i] = (int *) malloc(c * sizeof(int));
		}
		else {
/*			throw 1;
			throw "Il numero di righe o di colonne inserito non e' valido";*/
			throw "Errore";
		}
	}

	/*template <class TYPE> static void createMatrix (TYPE **ptr, int r, int c) {

		TYPE **temp;
		temp = (TYPE **) calloc(c, sizeof(TYPE *));
		for (int i = 0; i < r; i++) {
			temp[i] = (TYPE *) calloc(r, sizeof(TYPE));
		ptr = temp;
	}

	Matrix::Matrix(int **m) {
		//matrix = m;
		this -> rows = sizeof(m)/sizeof(int);
		this -> columns = sizeof(m)/(sizeof(*m)*sizeof(int));
	}*/

	// Getters e setters

	int Matrix::getRows() {
		return this -> rows;
	}
          
	int Matrix::getColumns() {
		return this -> columns;
	}

	// Restituisce la matrice sottoforma di stringa

	string Matrix::toString() {
		stringstream result;
		for (int i = 0; i < this -> rows; i++) {
			for (int j = 0; j < this -> columns; j++) {
				result << matrix[i][j] << " ";
			}
			result << endl;
		}
		return result.str();
	}
}
